package com.zyf.project.binaryproto.encoder.impl;

import com.zyf.project.binaryproto.encoder.SliceEncoder;
import com.zyf.project.binaryproto.specification.BinarySliceSpecification;
import org.jetbrains.annotations.NotNull;
import utils.binary.impl.BytesSlice;
import utils.binary.BytesSlices;
import utils.binary.BytesUtils;
import utils.binary.io.BytesInputStream;
import utils.binary.io.BytesOutputBuffer;
import utils.binary.impl.BytesSliceArrayWrapper;

/**
 * <h1>编码器头部</h1>
 * <p>编码器头部包含了数据格式标准、编码器编码、编码器版本、编码器名字、编码器描述这些信息</p>
 * <p>实际存储的时候，头部仅包含编码（4 字节）和版本（8 字节）两个信息，即 12 字节</p>
 *
 * @author Zhou Yifan
 */
public class HeaderEncoder implements SliceEncoder {

    /**
     * 编码器头部字节数，12 字节，即编码器编码（4 字节）和版本（8 字节）两个信息
     */
    public static final int HEAD_BYTES = 12;

    private BinarySliceSpecification sliceSpecification;

    private int code;

    private long version;

    private String name;

    private String description;

    /**
     * 编码器编码（头部的 4 个字节）
     *
     * @return int 值
     */
    public int getCode() {
        return code;
    }

    /**
     * 编码器版本（头部的第 5-12 个字节）
     *
     * @return int 值
     */
    public long getVersion() {
        return version;
    }

    /**
     * 编码器名字
     *
     * @return 字符串
     */
    public String getName() {
        return name;
    }

    /**
     * 编码器描述
     *
     * @return 字符串
     */
    public String getDescription() {
        return description;
    }

    public HeaderEncoder(BinarySliceSpecification sliceSpecification, int code, long version, String name, String description) {
        this.sliceSpecification = sliceSpecification;
        this.code = code;
        this.version = version;
        this.name = name;
        this.description = description;
    }

    /**
     * 校验指定的数据契约字节列表的头部的编码是否一致；
     *
     * @param dataContractBytes {@link BytesSlice}
     * @return 布尔值
     */
    public boolean verifyContractCode(BytesSlice dataContractBytes) {
        int code1 = resolveCode(dataContractBytes);

        // 忽略版本比较，这样可以实现多版本兼容解析
        // long version1 = resolveVersion(dataContractBytes);
        // return version1 == this.version;
        return code1 == this.code;
    }

    public static int resolveCode(@NotNull BytesSlice dataContractBytes) {
        return dataContractBytes.getInt();
    }

    public static long resolveVersion(@NotNull BytesSlice dataContractBytes) {
        return dataContractBytes.getLong(4);
    }


    /**
     * 获取格式标准
     *
     * @return {@link BinarySliceSpecification}
     */
    @Override
    public BinarySliceSpecification getSliceSpecification() {
        return sliceSpecification;
    }

    /**
     * 将数据序列化到指定缓存中
     *
     * @param dataContract 数据
     * @param buffer       指定缓存 {@link BytesOutputBuffer}
     * @return 写入的字节数
     */
    @Override
    public int encode(Object dataContract, @NotNull BytesOutputBuffer buffer) {
        byte[] headBytes = new byte[HEAD_BYTES];
        BytesUtils.toBytes(code, headBytes);
        BytesUtils.toBytes(version, headBytes, 4);
        buffer.write(headBytes);
        return HEAD_BYTES;
    }

    /**
     * 将 BytesInputStream 反序列化成数据片
     *
     * @param bytesInputStream {@link BytesInputStream}
     * @return {@link BytesSlices}
     */
    @Override
    public BytesSlices decode(@NotNull BytesInputStream bytesInputStream) {
        return BytesSliceArrayWrapper.wrap(bytesInputStream.readSlice(HEAD_BYTES));
    }
}
